package cn.stylefeng.guns.core.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Component
public class JPushUtil {

    private static final Logger log = LoggerFactory.getLogger(JPushUtil.class);
    private static final String JPUSH_PUSH_URL = "https://api.jpush.cn/v3/push";

    private final String appKey;
    private final String masterSecret;
    private final HttpClient httpClient;
    private final ObjectMapper objectMapper;

    public JPushUtil(
            @Value("${jpush.app-key:}") String appKey,
            @Value("${jpush.master-secret:}") String masterSecret
    ) {
        this.appKey = appKey;
        this.masterSecret = masterSecret;
        this.httpClient = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10))
                .build();
        this.objectMapper = new ObjectMapper();
    }

    public PushResult pushNotificationToAll(String alert, Map<String, Object> extras, String title) {
        return doPush("all", buildAndroidNotification(alert, title, extras), null);
    }

    public PushResult pushMessageToAll(String msgContent, Map<String, Object> extras) {
        return doPush("all", null, buildMessage(msgContent, extras));
    }

    public PushResult pushNotificationToRegistrationId(String registrationId, String alert, Map<String, Object> extras, String title) {
        Map<String, Object> audience = new LinkedHashMap<>();
        audience.put("registration_id", List.of(registrationId));
        return doPush(audience, buildAndroidNotification(alert, title, extras), null);
    }

    public PushResult pushMessageToRegistrationId(String registrationId, String msgContent, Map<String, Object> extras) {
        Map<String, Object> audience = new LinkedHashMap<>();
        audience.put("registration_id", List.of(registrationId));
        return doPush(audience, null, buildMessage(msgContent, extras));
    }

    public PushResult pushNotificationToAlias(String alias, String alert, Map<String, Object> extras, String title) {
        Map<String, Object> audience = new LinkedHashMap<>();
        audience.put("alias", List.of(alias));
        return doPush(audience, buildAndroidNotification(alert, title, extras), null);
    }

    public PushResult pushNotificationToTags(List<String> tags, String alert, Map<String, Object> extras, String title) {
        Map<String, Object> audience = new LinkedHashMap<>();
        audience.put("tag", tags);
        return doPush(audience, buildAndroidNotification(alert, title, extras), null);
    }

    private Map<String, Object> buildAndroidNotification(String alert, String title, Map<String, Object> extras) {
        Map<String, Object> android = new LinkedHashMap<>();
        android.put("alert", alert);
        if (title != null && !title.isEmpty()) {
            android.put("title", title);
        }
        if (extras != null && !extras.isEmpty()) {
            android.put("extras", extras);
        }
        Map<String, Object> notification = new LinkedHashMap<>();
        notification.put("android", android);
        return notification;
    }

    private Map<String, Object> buildMessage(String msgContent, Map<String, Object> extras) {
        Map<String, Object> message = new LinkedHashMap<>();
        message.put("msg_content", msgContent);
        if (extras != null && !extras.isEmpty()) {
            message.put("extras", extras);
        }
        return message;
    }

    private PushResult doPush(Object audience, Map<String, Object> notification, Map<String, Object> message) {
        if (appKey == null || appKey.isBlank() || masterSecret == null || masterSecret.isBlank()) {
            String err = "JPush appKey/masterSecret 未配置或为空";
            log.warn(err);
            return new PushResult(false, 0, null, err);
        }
        try {
            Map<String, Object> body = new LinkedHashMap<>();
            body.put("platform", "android");
            body.put("audience", audience);
            if (notification != null) {
                body.put("notification", notification);
            }
            if (message != null) {
                body.put("message", message);
            }

            String json = objectMapper.writeValueAsString(body);

            HttpRequest request = HttpRequest.newBuilder(URI.create(JPUSH_PUSH_URL))
                    .timeout(Duration.ofSeconds(10))
                    .header("Content-Type", "application/json")
                    .header("Authorization", basicAuthHeader())
                    .POST(HttpRequest.BodyPublishers.ofString(json, StandardCharsets.UTF_8))
                    .build();

            HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
            int status = response.statusCode();
            String respBody = response.body();
            boolean success = status == 200;

            if (!success) {
                log.warn("JPush 推送失败, status={}, body={}", status, respBody);
            } else {
                log.info("JPush 推送成功, body={}", respBody);
            }
            return new PushResult(success, status, respBody, success ? null : "HTTP " + status);
        } catch (Exception e) {
            log.error("JPush 推送异常", e);
            return new PushResult(false, 0, null, e.getMessage());
        }
    }

    private String basicAuthHeader() {
        String token = appKey + ":" + masterSecret;
        String base64 = Base64.getEncoder().encodeToString(token.getBytes(StandardCharsets.UTF_8));
        return "Basic " + base64;
    }

    public static class PushResult {
        private final boolean success;
        private final int status;
        private final String responseBody;
        private final String error;

        public PushResult(boolean success, int status, String responseBody, String error) {
            this.success = success;
            this.status = status;
            this.responseBody = responseBody;
            this.error = error;
        }

        public boolean isSuccess() { return success; }
        public int getStatus() { return status; }
        public String getResponseBody() { return responseBody; }
        public String getError() { return error; }
    }
}